﻿if not ArmorCraft_revision then ArmorCraft_revision = {} end
ArmorCraft_revision.main	= ("$Revision: 118 $"):match("(%d+)")
ArmorCraft_revision.toc  = GetAddOnMetadata("ArmorCraft", "Version"):match("%$Revision:%s(%d+)")


--[[ ArmorCraft: Find the best armor that can be crafted for a level.
    Written by Vincent of Blackhand, (copyright (c) 2005-2006 by D.A.Down)

	Version history (by LaoTseu)
	 20300-1 - Compatible with WoW 2.3.0 (TOC 20300)
	 			- Added Off-hand, Neck and Tricket slots
	 		   - Scale the windows to 0.8
	 		   - The use window is now different then the craft windows
	 		   - Now support formulas based on ItemBonusLib results
	 		   - Support for Jewelcrafting
	 		   - Return of the Loot Window compatibility
	 		   - Also compatible with the marchant window
    20100-1 - Compatible with WoW 2.1.0 (TOC 20100)
    20003-2 - Compatible with WoW 2.0.5 (BC)
            - Fix TOC to 20003 (stupid me)
            - Fix a problem with some ring that could not be compare with shift-click
	 20003-1 - Fix compatility with WoW 2.0.4


    Version history (by Vincent of Blackhad)
    1.9 - WoW 2.0 update.
    1.8.1 - Updated 'for' loops for Lua 5.1
    1.8 - Now uses CharacterProfiler data instead of CharactersViewer.
    1.7.3 - Added command line help (CmdHelp)
    1.7.2 - WoW 1.12 update.
    1.7.1 - WoW 1.11 update.
    1.7 - WoW 1.10 update.
    1.6.4 - Updated French localization (by Verdhit of Eitrigg)
    1.6.3 - Fixed loot window paste link to chat.
    1.6.2 - Shift-click on equipment pastes link in chat edit.
    1.6.1 - Added right-click of craft selection to skip.
    1.6 - Added comparison of loot, group loot and chat link items.
    1.5.3 - Added off-hand weapon comparison.
    1.5.2 - Fixed engineer trickets not being recognized.
    1.5.1 - Fixed bug with switching between slot #1 & #2
    1.5 - WoW 1.9 update.
    1.4.3 - Fixed some German words.
    1.4.2 - Updated German localization.
    1.4.1 - Fixed 40+ hunter to not use shields.
    1.4 - Expanded buf value table with values by class.
    1.3.3 - Fix for dynamic tradeskill loading in WoW 1.8
    1.3.2 - Corrected weapon use table for axes.
    1.3.1 - WoW 1.7 update.
    1.3 - Added 2 slots and weapon crafting selection.
    1.2.6.1 - Fixed some minor item comparison logic errors.
    1.2.6 - Added support for MPO and '/ac <GCV name>'.
    1.2.5 - Added support for GCV and neck/ring/trinket items.
    1.2.4 - Added support for shields and off-hand trinkets.
    1.2.3 - Added support for comparing party member items.
    1.2.2 - Removed debug call.
    1.2.1 - Added armor or weapon comparison for target player.
    1.2 - Added armor or weapon comparison for CV characters.
    1.1.2 - Added paired tooltip for easier comparison.
    1.1.1 - Updated for CharactersViewer 0.67 compatability.
    1.1 - Displays calculated value and accepts custom values.
    1.0.2 - Moves the AC button if KC_EnhancedTrades is present.
    1.0.1 - Updated French localization.
    1.0 - Adds attribute weighting to prefered armor selection.
    0.8 - Adds support for CharactersViewer target selection.
    0.7 - Adds a target window for comparing equipment.
    0.6.3 - Adds AC button to trade skill window.
    0.6.2 - WoW 1.6, current chat window, German localization.
    0.6.1 - added target selection and 40+ upgrade.
    0.6 -  Initial public release.
]]--

-- Local function prototypes

-- Local data
local AC = {}

--local ibl = AceLibrary("ItemBonusLib-1.0")
local ibl = LibStub("LibItemBonus-2.0")


local FCg 		= "|cff40c040" -- Green
local FCr 		= "|cffff0000" -- Red
local FCw 		= "|cffffffff" -- White
local FCy 		= "|cff9d9d9d" -- Grey
local FCgold 	= "|cffffd700" -- Gold
local White 	= {r=1,g=1,b=1}
local Gray 		= {r=0.5,g=0.5,b=0.5}
local Green 	= {r=0,g=1,b=0}
local Red 		= {r=1,g=0,b=0}
--local CP_nr = 0

--[[
local FCrare = {[0]="|cff9d9d9d","|cffffffff","|cff1eff00","|cff0070dd",
                    "|cffa335ee","|cffff8000","|cff57BDFB"}
]]--
local function ItemLink(item)
   local _,ilink,_ = GetItemInfo(item)
	return ilink
end

local function LinkItem(link)
    if link then
--      local i,j,item = strfind(link,"(item:%d+:%d+:%d+:%d+:%d+:%d+:%d+:%d+)")
      local found, _, itemString = string.find(link, "^|%x+|H(.+)|h%[.+%]")
      return itemString
    end
end

local function AC_Is2H(link)
    ArmorCraft_TT:SetHyperlink(link)
    local desc = AC_Parse()
    return desc.loc==AC_TWO
end

local function sorted_index(table)
    local index = {}
    for key in pairs(table) do tinsert(index,key) end
    sort(index)
    return index
end

-- Global data
if not ArmorCraft then ArmorCraft = {} end

-- Settings
ArmorCraft.ignore_enchant = true
ArmorCraft.ignore_jewel   = true

AC_Ignore = AC_Ignore or {}
ArmorCraft.ignore = AC_Ignore

----------------------
-- Temporary variables
----------------------

-- Init tables
ArmorCraft.cache = {}
ArmorCraft.ID_to_slotname = {}
ArmorCraft.tradeskill_skip = {}

-- Current AC focus type
-- Possible values: player, target, partyN, number (for recorded values)
ArmorCraft.unit_id = "player"

-- For the AC_use window
ArmorCraft.use_link = nil				-- Current item compared in the AC_Use window

-- For the recorded characters
ArmorCraft.recorder					= ""
ArmorCraft.recorded_number 		= 0
ArmorCraft.recorded_name_list		= {}

-- print functions
function ArmorCraft:print(msg) SELECTED_CHAT_FRAME:AddMessage("AC: "..msg,0.5,1,0) end
function ArmorCraft:debug(msg) if ACdebug then print(msg) end end

local function print(...) ArmorCraft:print(...) end
local function debug(...) ArmorCraft:debug(...) end

AC_Unit = "player"
--ArmorCraft_ix = {[AC_GUNS]=12}
ArmorCraft_Class_ix = {}
--ArmorCraft_CP_ix = {}
ArmorCraft_Value = {}


function ArmorCraft_Init()
	-- Get the revision number
	ArmorCraft.revision = 0
	if ArmorCraft_revision then
		for _, rev in pairs(ArmorCraft_revision) do
			local revision = tonumber(rev)
			if revision and revision > ArmorCraft.revision then ArmorCraft.revision = revision end
		end
	else
		assert(false,"No ArmorCraft_revision")
	end

	-- Initialize formula values in SaveVariables
	if not ArmorCraft_Formulas then ArmorCraft_Formulas = {} end
	if not ArmorCraft_Formula_to_Use then ArmorCraft_Formula_to_Use = {} end

	for key, formula in pairs(AC_Formula) do
		if not ArmorCraft_Formulas[key] then ArmorCraft_Formulas[key] = formula end
	end

	for key, table in pairs(AC_Formula_to_Use) do
		if not ArmorCraft_Formula_to_Use[key] then
			ArmorCraft_Formula_to_Use[key] = table
		else
			for loc, name in pairs(table) do
				if not ArmorCraft_Formula_to_Use[key][loc] then
					ArmorCraft_Formula_to_Use[key][loc] = name
				end
			end
		end
	end

--    UIPanelWindows["AC_Use"] = {area="left", pushable=7}

    if TradeSkillFrame then AC_SetFrames() end
    -- add our chat commands
    SlashCmdList["AC"] = ArmorCraft_command
    SLASH_AC1 = "/armorcraft"
    SLASH_AC2 = "/ac"
    SlashCmdList["ACV"] = ArmorCraft_value
    SLASH_ACV1 = "/acv"
--    SlashCmdList["ACIU"] = ArmorCraft_ItemUse
--    SLASH_ACIU1 = "/itemuse"
--    SLASH_ACIU2 = "/iu"
--    if not AC_Value or not AC_Value[AC_MAGE] then AC_Value = ArmorCraft_Attr end

    -- Catch all hook for secure windows with loot and items
    hooksecurefunc("HandleModifiedItemClick", AC_HandleModifiedItemClick)

    -- hook Chat OnCLick
    AC_ChatOnClick_Save = ChatFrame_OnHyperlinkShow
    ChatFrame_OnHyperlinkShow = AC_ChatOnClick

    -- set up the location table
    local button,id
    for name,loc in pairs(ArmorCraft_Loc) do
      loc.slotID,loc.tex = GetInventorySlotInfo(loc.slot)
      id = loc.ID
      if id then
        button = getglobal("AC_CraftButton"..id)
        if button ~= nil then button.loc = name end
        button = getglobal("AC_TargetButton"..id)
        if button ~= nil then button.loc = name end

        -- Set up the ID to SlotName correspondance table
		  ArmorCraft.ID_to_slotname[loc.SlotID] = loc.slot
      end
    end

    ArmorCraft_Class_ix = sorted_index(ArmorCraft_Class)
    -- CmdHelp loaded check
    if not CmdHelp then CmdHelp = function () end end

	-- Initialisation hook with CharacterProfiler type addon
	AC_InitRecordedCharacter()

	-- Initialisation of options
   ArmorCraft:InitOptions()
end

function ArmorCraft_OnShow()
    if KC_EnhancedTrades_TSFButton then
      AC_ToggleButton:SetPoint("RIGHT","KC_EnhancedTrades_TSFButton","LEFT",2,0)
    elseif AckisRecipeList and _G['addon.ScanButton'] then
      AC_ToggleButton:SetPoint("RIGHT","addon.ScanButton","LEFT",2,0)
    else
    	AC_ToggleButton:SetPoint("RIGHT","TradeSkillFrameCloseButton","LEFT")
    end
    AC_tsname = GetTradeSkillLine()
    if AC_tsname and ArmorCraft_TS[AC_tsname] then
      AC_ToggleButton:Enable()
      AC_UseButton:Enable()
    elseif AC_tsname==AC_ENG then AC_UseButton:Enable()
    else
    	AC_ToggleButton:Disable(); AC_UseButton:Disable()
    end
end

-- Check for proper trade skill window open
local function AC_TScheck()
    local nts = GetNumTradeSkills()
    AC_tsname = GetTradeSkillLine()
    if nts==0 or AC_tsname=="UNKNOWN" then
      print(FCr..ARMORCRAFT_NOWINDOW)
      return true
    end
--    local AC_Type = ArmorCraft_TS[AC_tsname]
    if not ArmorCraft_TS[AC_tsname] then
      print(FCr..AC_tsname..ARMORCRAFT_NOTARMOR)
      return true
    end
end


-- Function that validated that the right combinasion of button/modifier keys
-- has been pressed.
-- It also validate that the Chat Edit box (where ppl type message) is not there.
local function ClickOK(ignoreButton)
--[[print(format("ClickOK: Shift=%s, CTRL=%s,ALT=%s,Button=%s,IsVisible=%s",
				 IsShiftKeyDown() or "nil",
				 IsControlKeyDown() or "nil",
				 IsAltKeyDown() or "nil",
				 GetMouseButtonClicked() or "nil",
				 ChatFrameEditBox:IsVisible() or "nil"
      )
)]]--
	return     IsShiftKeyDown() and
			 not IsControlKeyDown() and
			 not IsAltKeyDown() and
			     (GetMouseButtonClicked() == "LeftButton" or ignoreButton) and
			 not ChatFrameEditBox:IsVisible()
end

-- Handle Chat OnClick events
function AC_ChatOnClick(self,link,text,button,...)
	local ok = strsub(link,1,5)=='item:' and button=="LeftButton"
	if ClickOK(true) and ok then
		ArmorCraft_TT:SetOwner(AC_Frame)
		ArmorCraft_TT:SetHyperlink(link)
		ArmorCraft_WhoCanUse(link)
	else AC_ChatOnClick_Save(self,link,text,button,...) end
end

-- Old style Chat OnClick
function AC_ChatOnClickOld(item,link,button,...)
    local ok = strsub(item,1,5)=='item:' and button=="LeftButton"
    if ClickOK(true) and ok then
      ArmorCraft_TT:SetOwner(AC_Frame)
      ArmorCraft_TT:SetHyperlink(item)
      ArmorCraft_WhoCanUse(link)
    else AC_ChatOnClick_Save(item,link,button,...) end
end

-- General HandleModifiedItemClick hook
function AC_HandleModifiedItemClick(link)
debug(format("AC_HandleModifiedItemClick: link = %s",link or "X"))
	if ClickOK() then
		-- Is this single item and is it equipable?
local button = GetMouseButtonClicked()
		local _, _, _, _, _, _, _, itemStackCount, itemEquipLoc = GetItemInfo(link)
debug(format("AC_HandleModifiedItemClick: button = %s, itemStackCount = %s, itemEquipLoc =%s",button or "X",itemStackCount or "X",itemEquipLoc or "X"))
		if itemStackCount == 1 and itemEquipLoc and ArmorCraft_EquipWhere[itemEquipLoc] then
			ArmorCraft_TT:SetOwner(AC_Frame)
			ArmorCraft_TT:SetHyperlink(link)
			ArmorCraft_WhoCanUse(link)
		end
	end
end

-- Handle craft item use
function ArmorCraft_CraftUse()
--    local TSname = GetTradeSkillLine()
    local tsi = GetTradeSkillSelectionIndex()
    if tsi<1 then print(FCd..ARMORCRAFT_NOITEM) return end
    ArmorCraft_WhoCanUse(GetTradeSkillItemLink(tsi))
end

function AC_PartyOnClick()
    AC_Name = ''
    --ArmorCraft_TT:SetOwner(AC_Frame)
    --ArmorCraft_TT:SetHyperlink(LinkItem(AC_Link))
    ArmorCraft_WhoCanUse(ArmorCraft.use_link)
end

function AC_RadioButton_OnClick(id,init)
    AC_UseSlot1Button:SetChecked(id==1)
    AC_UseSlot2Button:SetChecked(id==2)
    if init then return end
    AC_Name = ''
--    ArmorCraft_TT:SetOwner(AC_Frame)
--    ArmorCraft_TT:SetHyperlink(LinkItem(ArmorCraft.use_link))
    ArmorCraft_WhoCanUse(ArmorCraft.use_link)
end

-- #################################################################################
-- #################################################################################
-- ##
-- ## AC_AValue(desc,class,loc)
-- ## -------------------------
-- ##
-- ## Return the comparative value based on the item information in the desc table
-- ##
-- ## Parameter: desc (table)  	= Information about the item (see AC_Parse)
-- ## 			  class (string)	= Class that must be evaluated
-- ## 			  loc (string)    = location of the item to evaluate
-- ##										  (default to desc.loc)
-- ##										  The format is the same as itemEquipLoc returned by
-- ##										  GetItemInfo
-- ##
-- ##
-- #################################################################################

local meta = {["__index"] = function() return 0 end}
local function AC_AValue(desc,class,loc)
debug(format("AC_AValue: link=%s, class=%s, loc=%s",desc.link or "nil",class or "nil",loc or "nil"))
	-- No location = not usable
	if (not loc and not desc.loc) or not desc.link then return 0 end

	-- Use the global class if none if pass to the function
--	if class == nil then class = AC_Class end

	-- Use the parameter location or the object one
--	loc = loc or desc.loc
	assert(loc,"loc is nil")

	-- Link to use
	local itemLink = desc.link

	local found, _, itemString = string.find(itemLink, "^|c%x+|H(.+)|h%[.+%]")
	if not found then
		print(FCr..ARMORCRAFT_INVALIDLINK..itemLink)
	end

	local _, itemId, enchantId, jewelId1, jewelId2, jewelId3, jewelId4, suffixId, uniqueId = strsplit(":", itemString)

	if ArmorCraft.ignore_enchant then
		-- Remove the enchant part of the link if it exists
		enchantId = 0
	end

	if ArmorCraft.ignore_jewel then
		-- Remove the jewel parts of the link if they exsits
		jewelId1, jewelId2, jewelId3, jewelId4 = 0, 0, 0, 0
	end

	itemString = strjoin(":", "item", itemId, enchantId, jewelId1, jewelId2, jewelId3, jewelId4, suffixId, uniqueId)
debug("AC_AValue: itemString = "..itemString)

	-- Is it already in the cash?
	if ArmorCraft.cache[class..'|'..itemString..'|'..loc] then return ArmorCraft.cache[class..'|'..itemString..'|'..loc] end

	-- Find the right formula
	local formula
	local formula_loc

	if ArmorCraft_Formula_to_Use[class][loc] ~= nil then
		formula_loc = loc
		formula = ArmorCraft_Formulas[ArmorCraft_Formula_to_Use[class][loc]]
	else
		formula_loc = DEFAULT
		formula = ArmorCraft_Formulas[ArmorCraft_Formula_to_Use[class][DEFAULT]]
	end

	-- Get the bonus for the item
	local bonus 		= ibl:ScanItem(itemString, true)

	-- Add our own values
	if bonus["WEAPON_SPEED"] then
	   bonus["AVG_DMG"] 			= (bonus["WEAPON_MIN"]+bonus["WEAPON_MAX"])/2
		bonus["DPS"] 				= bonus["AVG_DMG"]/bonus["WEAPON_SPEED"]
		bonus["OH_SPEED_COEF"]	= (2.9-bonus["WEAPON_SPEED"])*10
	else
	   bonus["AVG_DMG"] 			= 0
		bonus["DPS"] 				= 0
		bonus["OH_SPEED_COEF"] 	= 0
	end

	bonus["AC"] = bonus["ARMOR"] or 0
	bonus["APR"] = bonus["CR_ARMOR_PENETRATION"] or 0
	bonus["BLUE"] = bonus["EMPTY_SOCKET_BLUE"] or 0
	bonus["RED"] = bonus["EMPTY_SOCKET_RED"] or 0
	bonus["YELLOW"] = bonus["EMPTY_SOCKET_YELLOW"] or 0
	bonus["META"] = bonus["EMPTY_SOCKET_META"] or 0

	-- Make the non existing values return 0
	ArmorCraft.data  	= setmetatable(bonus, meta)

	-- Parse the formula using the bonus table as local variables
	local av = loadstring("local math=math;setfenv(1, ArmorCraft.data);return " .. formula)()
--print(format("AC_AValue: av=%s, formula=%s",av or "nil",formula or "nil"))

	-- Clean up
	setmetatable(bonus, nil)
	ArmorCraft.data   = nil

--print(desc.name .."("..class..","..desc.loc..") = "..tostring(av or 0))
	ArmorCraft.cache[class..'|'..itemString..'|'..formula_loc] = av or 0
   return ArmorCraft.cache[class..'|'..itemString..'|'..formula_loc]
end

-- #################################################################################
-- #################################################################################
-- ##
-- ## ArmorCraft_WhoCanUse(newItemLink)
-- ## ---------------------------------
-- ##
-- ## Display the AC_Use window for all the members of the party or all the alt
-- ## recorded with indication if the item is an upgrade.
-- ##
-- ## Any item that can be use or can eventually be use with leveling or talent
-- ## respect will be displayed.
-- ##
-- ## Parameter: newItemLink	= itemLink for the item to be compared.
-- ##
-- #################################################################################

function ArmorCraft_WhoCanUse(newItemLink)
	-- If the window is already diplayed, we just received an order to hide it
	if ArmorCraft.use_link == newItemLink and AC_Use:IsVisible() and AC_Name == UnitName("target") then
		ArmorCraft.use_link = nil
		HideUIPanel(AC_Use)
		return
	end


	-- Keep the link for has long as the window is displayed
	ArmorCraft.use_link = newItemLink

	-- Get the Equipment location that will be used to generate the item value
	-- and to find items to compare with
	local _, _, _, _, _, useItemType, _, _, useEquipLoc = GetItemInfo(newItemLink)

	-- Verify if it is an allowed type of item
	if not useItemType or (useItemType ~= AC_ARMOR and useItemType ~= AC_WEAPON) then
	   print(FCr..ARMORCRAFT_WRONG..useItemType)
	   return
	end

	-- Hide the tradecraft window if there
	HideUIPanel(AC_Craft)

	-- Show the use window
	--SetUIPanel('center', AC_Use, true)
	ShowUIPanel(AC_Use)
	SetPortraitTexture(AC_UsePortrait,"player")

	-- Parse the item to compare
	-- Bind the item to the hiden ToolTip
	ArmorCraft_TT:SetOwner(AC_Frame)
	ArmorCraft_TT:SetHyperlink(newItemLink)
	local descToCompare = AC_Parse(false)

	-- Are we using the Party pop-up?
	local numberInParty = GetNumPartyMembers()


	-- We have a button to display only if there is more then 1 recorded character
	-- and there is a party
	if ArmorCraft.recorded_number < 2 or numberInParty == 0 then
		AC_UsePartyButton:Hide()
	else
		AC_UsePartyButton:Show()
	end

--print(format("WCU: useEquipLoc = %s",useEquipLoc))
	-- Do we need have more then one possible equipement to compare?
	local tagetSlotChoices 	= ArmorCraft_EquipWhere[useEquipLoc]

	if #tagetSlotChoices > 1 then
		AC_UseSlot1Button:Show()
		AC_UseSlot2Button:Show()
--		if not AC_UseSlot2Button:GetChecked() then
--			AC_UseSlot2Button:SetChecked(true)
--		end
	else
		AC_UseSlot1Button:SetChecked(true)
		AC_UseSlot2Button:SetChecked(false)
		AC_UseSlot1Button:Hide()
		AC_UseSlot2Button:Hide()
	end

	local currentTargetSlotChoice = AC_UseSlot2Button:GetChecked() or 1

	-- Do we iterate a party or recorded character?
--print(format("WCU: numberInParty = %s, GetChecked() = %s",numberInParty,AC_UsePartyButton:GetChecked()))
--print(format("WCU: ArmorCraft.recorded_number = %s",ArmorCraft.recorded_number))
--print(format("WCU: currentTargetSlotChoice = %s",currentTargetSlotChoice))
--print(format("WCU: tagetSlotChoices[currentTargetSlotChoice] = %s",tagetSlotChoices[currentTargetSlotChoice]))

	if numberInParty > 0 and AC_UsePartyButton:GetChecked() then
		for index=0,9 do
			local UnitID
			-- In party mode, the first unit will be the player
			if index == 0 then
				UnitID = "player"
			elseif index <= numberInParty then
				UnitID = "party" .. index
			else
				-- button is empty
				UnitID = "none"
			end

			-- Set the button
			ArmorCraft_SetUseButton(index+1,UnitID,descToCompare,tagetSlotChoices[currentTargetSlotChoice])
		end
	elseif ArmorCraft.recorded_number > 1 then
		for index=1,10 do
			if index <= ArmorCraft.recorded_number then
				ArmorCraft_SetUseButton(index,index,descToCompare,tagetSlotChoices[currentTargetSlotChoice])
			else
				ArmorCraft_SetUseButton(index,"none",descToCompare,tagetSlotChoices[currentTargetSlotChoice])
			end
		end
	else -- It's only the curent characteur i.e. "player" and possibly the "target"
--		SetPortraitTexture(AC_UsePortrait,"target")
		ArmorCraft_SetUseButton(1,"player",descToCompare,tagetSlotChoices[currentTargetSlotChoice])

		for index=2,10 do
			if index == 2 and UnitName("target") then
				ArmorCraft_SetUseButton(2,"target",descToCompare,tagetSlotChoices[currentTargetSlotChoice])
			else
				ArmorCraft_SetUseButton(index,"none",descToCompare,tagetSlotChoices[currentTargetSlotChoice])
			end
		end
	end
end

-- #################################################################################
-- #################################################################################
-- ##
-- ## ArmorCraft_SetUseButton(buttonID,unitID,descToCompare,targetSlot)
-- ## -----------------------------------------------------------------
-- ##
-- ## This function set a button of the AC_Use window.
-- ##
-- ## Parameters:	buttonID			= the id of the current button to set (1 to 10)
-- ## 				unitID			= "player","target","partyN", "none" or a number
-- ## 									  indicate where to get the character information
-- ## 									  If it is a number, the information comes from a
-- ## 									  recorded character
-- ## 				descToCompare	= desc table for the item that need to be compare
-- ## 									  with whatever the character is holding in a
-- ## 									  particular item slot.
-- ## 				targetSlotID	= InventorySlotId for to use on the character
-- ## 									  for comparaison
-- ##
-- #################################################################################

function ArmorCraft_SetUseButton(buttonID,unitID,descToCompare,targetSlotID)
	-- Find the curent button
	local button = getglobal("AC_UseButton"..(buttonID))
	local label  = getglobal("AC_UseButton"..(buttonID).."Text")

	-- Working variables
	local _, useItemLink, _, _, useItemMinLevel, useItemType, useItemSubType, _, useEquipLoc = GetItemInfo(descToCompare.link)

	-- If unitID is "none", we just empty the button
	if unitID == "none" then
		-- Button must be empty
		local _, texture = GetInventorySlotInfo(ArmorCraft.ID_to_slotname[targetSlotID])
		SetItemButtonTexture(button,texture)
		button.new_item_link 	= nil
		button.char_item_link 	= nil
		button.new_item_value 	= nil
		button.char_item_value 	= nil
		label:SetText('')
		label:SetTextColor(White.r, White.g, White.b)

		-- Legacy stuff
		button.slot 				= nil
		button.av   				= nil

		return
	end

	-- Character information
	local characterName, characterClass, characterLevel, characterItemLink, characterItemTexture

	-- Is this a recorded character?
	local recordNo = tonumber(unitID)
	if recordNo then
		characterName = ArmorCraft.recorded_name_list[recordNo]

		-- If the curent recorded character is the player, we use fetch the information
		-- directly
		if characterName == UnitName("player") then
			-- This will be
			characterClass		= UnitClass("player")
			characterLevel		= UnitLevel("player")
			characterItemLink	= GetInventoryItemLink("player",targetSlotID)
		else
--print(format("SUB: characterName = %s, slotName = %s",characterName or 'nil',ArmorCraft.ID_to_slotname[targetSlotID] or 'nil'))
			characterClass, characterLevel = AC_GetRecordedCharacterInfo(characterName)
			characterItemLink = AC_GetRecordedCharacterEquip(characterName, targetSlotID)
		end
	else
		characterName 		= UnitName(unitID)
		characterClass		= UnitClass(unitID)
		characterLevel		= UnitLevel(unitID)
		characterItemLink	= GetInventoryItemLink(unitID,targetSlotID)
	end

--print(format("SUB: characterItemLink = %s",characterItemLink or 'nil'))

	-- Is it any good?
	button.new_item_value 	= AC_AValue(descToCompare,characterClass,useEquipLoc)
	if characterItemLink then
		ArmorCraft_TT:SetOwner(AC_Frame)
		ArmorCraft_TT:SetHyperlink(characterItemLink)
		local desc = AC_Parse(false)
		button.char_item_value = AC_AValue(desc,characterClass,useEquipLoc)
	else
		button.char_item_value = 0
	end

	-- Can the character use the item?
	if AC_CanUseItem(useItemLink,characterClass) then
		local colorName 	= FCw
		local colorType 	= FCw
		local colorLevel	= FCw
		-- Can the character use the item right now?
		if AC_CanUseItem(useItemLink,characterClass,characterLevel) then

			-- Color the name based on the relative value of the item
			if button.new_item_value > button.char_item_value then
				if button.new_item_value > button.char_item_value + 10 then
					-- The name is in gold if the item is real good
					colorName = FCgold
				elseif button.new_item_value > button.char_item_value + 2 then
					-- The name is green if the item is good
					colorName = FCg
				end
			elseif button.new_item_value < button.char_item_value - 2 then
				-- The name is in grey if the item is not really worth it
				colorName = FCy
			end
		else
			-- Why not?
			if useItemMinLevel > characterLevel then colorLevel = FCr end
			if ArmorCraft_CanUse[characterClass][useItemType][useItemSubType] > characterLevel then
				colorType = FCr
			end
		end

		-- For the base armor type, we display the best armor type possible for the character instead of the itemSubType
		if ArmorCraft_Types[useItemSubType] then
			if ArmorCraft_Class2[characterClass] and characterLevel >= 40 then
				-- Is it the optimum type for the class? (Only check for armor)
				if useItemSubType == ArmorCraft_Class2[characterClass] then
					colorType = FCg
				else
					useItemSubType = ArmorCraft_Class2[characterClass]
				end
			else
				-- Is it the optimum type for the class? (Only check for armor)
				if useItemSubType == ArmorCraft_Class[characterClass] then
					colorType = FCg
				else
					useItemSubType = ArmorCraft_Class[characterClass]
				end
			end
		end

		-- Use short descriptions when the original one is to long
		if AC_ShortDesc[useItemSubType] then useItemSubType = AC_ShortDesc[useItemSubType] end

		-- Time to display the label
		label:SetFormattedText("%s%s\n%s%s\n%s%s %s",
									  colorName,characterName,
									  colorType,useItemSubType,
									  colorLevel,characterClass,characterLevel)
		label:SetTextColor(White.r, White.g, White.b)

		-- Set the texture
		local Texture
		if characterItemLink then
			_, _, _, _, _, _, _, _, _, Texture = GetItemInfo(characterItemLink)
		else
			_, Texture = GetInventorySlotInfo(ArmorCraft.ID_to_slotname[targetSlotID])
		end
		SetItemButtonTexture(button,Texture)

		-- Set the other information for the button
		button.new_item_link 	= useItemLink
		button.char_item_link 	= characterItemLink
	else
		-- Button must be empty
		local _, Texture = GetInventorySlotInfo(ArmorCraft.ID_to_slotname[targetSlotID])
		SetItemButtonTexture(button,Texture)
		button.new_item_link 	= nil
		button.char_item_link 	= nil
		button.new_item_value 	= nil
		button.char_item_value 	= nil

		-- Use short descriptions when the original one is to long
		if AC_ShortDesc[useItemSubType] then useItemSubType = AC_ShortDesc[useItemSubType] end
		label:SetText(format("%s\n%s%s cannot use %s",
								   characterName,
								   AC.ColorClass(characterClass),
								   FCr,
								   useItemSubType))
		label:SetTextColor(White.r, White.g, White.b)

		-- Legacy stuff
 		button.slot 				= nil
		button.av   				= nil
	end
end

-- handle our chat command /ac
function ArmorCraft_command(name)
    if name=='debug' then
      ACdebug = not ACdebug
      print("Debug is "..(ACdebug and 'on' or 'off'))
      return
    end
    if name=='config'then
		ArmorCraft:DisplayOptions()
		return
    end
    if name=='reset' then
		-- Reset the formulas and the formulas assignation variables
		print(ARMORCRAFT_RESET)

		if not ArmorCraft_Formulas then ArmorCraft_Formulas = {} end
		if not ArmorCraft_Formula_to_Use then ArmorCraft_Formula_to_Use = {} end

		for key, formula in pairs(AC_Formula) do
			ArmorCraft_Formulas[key] = formula
		end

		for key, table in pairs(AC_Formula_to_Use) do
			ArmorCraft_Formula_to_Use[key] = table
		end

		-- Also reset the cache
		ArmorCraft.cache = {}

		return
    end
    if AC_Craft:IsVisible() and name=='' then
      HideUIPanel(AC_Craft)
      return
    end
    if name~='' and CmdHelp(AC_Help,'ac',name) then return end
    if AC_TScheck() then return end
    HideUIPanel(AC_Use)
    if name~='' and AC_Target:IsVisible() then
      AC_CP_DropDown_OnClick(name)
      return
    end
--    AC_Skip = {}
    ArmorCraft.tradeskill_skip = {}
    AC_Unit = "target"
    if not UnitIsPlayer(AC_Unit) then AC_Unit = "player" end
    SetPortraitTexture(AC_CraftPortrait,"player")
    SetPortraitTexture(AC_TargetPortrait,AC_Unit)
    name = UnitName(AC_Unit)
    AC_TargetTitle:SetText(name)
    AC_Level = UnitLevel(AC_Unit)
    AC_Class = UnitClass(AC_Unit)
--    local AC_Type = AC_Get_Type(AC_Class)
    if not AC_Get_Type(AC_Class) then
      print(FCr.."Undefined class: "..AC_Class)
      return
    end
    AC_MaxLevel:SetText(AC_Level)
    AC_MaxLevel:HighlightText(0,-1)
		UIDropDownMenu_SetWidth(AC_DropDown,90)
		UIDropDownMenu_Initialize(AC_DropDown,AC_DropDown_Init)
		UIDropDownMenu_SetText(AC_DropDown,AC.ColorClass(AC_Class))
	 UIDropDownMenu_SetSelectedValue(AC_DropDown,AC_Class)
--    AC_Craft:Show()
    ShowUIPanel(AC_Craft)
    if ArmorCraft.recorded_name_list then
    	if not AC_GetRecordedCharacterInfo(name) then name = AC_SELECT end
      --if not ArmorCraft.recorded_name_list[name] then name = AC_SELECT end
		UIDropDownMenu_SetWidth(AC_CP_DropDown,90)
		UIDropDownMenu_Initialize(AC_CP_DropDown,AC_CP_DropDown_Init)
		UIDropDownMenu_SetText(AC_CP_DropDown,name)
      UIDropDownMenu_SetSelectedValue(AC_CP_DropDown,name)
    end
--    AC_Target:Show()
	 ShowUIPanel(AC_Target)
    --AC_Scan(AC_Level)
    AC_ScanTradeSkillWindow(AC_Class,AC_Level,(AC_Unit~="player"))
end

-- handle our chat command /acv
function ArmorCraft_value(msg)
	if msg~='' and CmdHelp(AC_Help,'acv',msg) then return end
	if name=='default' then
		-- Reset the formulas and the formulas assignation variables
		print(ARMORCRAFT_RESET)

		if not ArmorCraft_Formulas then ArmorCraft_Formulas = {} end
		if not ArmorCraft_Formula_to_Use then ArmorCraft_Formula_to_Use = {} end

		for key, formula in pairs(AC_Formula) do
			ArmorCraft_Formulas[key] = formula
		end

		for key, table in pairs(AC_Formula_to_Use) do
			ArmorCraft_Formula_to_Use[key] = table
		end

		-- Also reset the cache
		ArmorCraft.cache = {}

		return
	elseif msg=='cache' then
    	-- Display the cache (mostly for debug but some user may like it
      local n = 0
      sorted_keys = {}
      for key in pairs(ArmorCraft.cache) do table.insert(sorted_keys,key) end
      table.sort(sorted_keys)
      for _,key in ipairs(sorted_keys) do
			local class,itemString,location = strsplit('|',key)
			print(format("%s %s %s = %s",class,ItemLink(itemString),location,ArmorCraft.cache[key]))
			n = n+1
      end
      if n==0 then print(ARMORCRAFT_EMPTY) end
      return
   elseif msg=='resetcache'then
   	-- Empty the value cash
		print(ARMORCRAFT_DELETECACHE)
   	ArmorCraft.cache = {}
   elseif msg=='formula' then
		for _,key in ipairs(sorted_index(ArmorCraft_Formula_to_Use)) do
			local class = key
			for _,key in ipairs(sorted_index(ArmorCraft_Formula_to_Use[class])) do
				local formula = key
				print(format("Formula for %s %s =",class,formula))
				if ArmorCraft_Formulas[ArmorCraft_Formula_to_Use[class][formula]] then
					print(" "..ArmorCraft_Formulas[ArmorCraft_Formula_to_Use[class][formula]])
				else
					print(FCr.."  Undefined Formula: "..formula)
				end
			end
		end
	end
--[[
    elseif msg~='' then
      local value = tonumber(msg)
      if value then
        if AC_TScheck() then return end
        local tsi = GetTradeSkillSelectionIndex()
        if tsi==0 then
          print(FCr..ARMORCRAFT_NOITEM)
          return
        end
        local link = GetTradeSkillItemLink(tsi)
        if value==0 then
          ArmorCraft_Value[link] = nil
          print(link..ARMORCRAFT_RESET)
          return
        end
        ArmorCraft_Value[link] = value;
        print(format("%s = %d",link,value))
        return
      end
      if strsub(msg,1,1)>'Z' then
        msg = strupper(strsub(msg,1,1))..strsub(msg,2)
      end
      local i,j,attr,nr = strfind(msg,"^(%a+)=(%d+)$")
      if not nr then
        print(FCr..ARMORCRAFT_BADFORMAT..msg)
        return
      end
      if not AC_Class then print(FCr..ARMORCRAFT_NOCLASS) return end
      if not AC_Value[AC_Class][attr] then
        print(FCr..ARMORCRAFT_UNDEFINED..attr)
        return
      end
      AC_Value[AC_Class][attr] = tonumber(nr)
    end
    if not AC_Class then print(FCr..ARMORCRAFT_NOCLASS) return end
    local str = ''
    print(format(ARMORCRAFT_CLASS,AC_Class))
    for attr,nr in pairs(AC_Value[AC_Class]) do
      if(str~='') then str = str..', ' end
      str = str..format("%s=%d",attr,nr)
    end
    print(str)
]]--
end

function AC_Get_Type(class)
    local Type = ArmorCraft_Class2[class]
    if(AC_Level<40 or not Type) then
      Type = ArmorCraft_Class[class]
    end
    return Type
end

function AC_DropDown_Init()
    local info
    for ix,class in pairs(ArmorCraft_Class_ix) do
--      info = {text=AC.ColorClass(class), value=ix, func=AC_DropDown_OnClick}
      info = {text=AC.ColorClass(class), value=class, func=AC_DropDown_OnClick}
      if class==AC_Class then info.checked = 1 end
      UIDropDownMenu_AddButton(info)
    end
end

function AC_CP_DropDown_Init()
    local info
    for ix,name in pairs(ArmorCraft.recorded_name_list) do
      info = {text=name, value=name, func=AC_CP_DropDown_OnClick}
      UIDropDownMenu_AddButton(info)
    end
end

function AC_DropDown_OnClick(self)
	if self.value then
		AC_Class = self.value
		UIDropDownMenu_SetSelectedValue(AC_DropDown,self.value)
		AC_ScanTradeSkillWindow(AC_Class,AC_Level,(ArmorCraft.unit_id~="player"))
	end
end

function AC_CP_DropDown_OnClick(self)
    local name = self
		if not name or type(name) == 'table' then
			name = self.value
		end

	local Class, Level, Texture = AC_GetRecordedCharacterInfo(name)

	if Class then
		-- We are using the recorded values
		ArmorCraft.unit_id = "recorded"

    	-- Legacy stuff
      --CP_Char = AC_CP_Chars[name]
      --AC_Unit = CP_Char.Equipment
      AC_Level = Level
      AC_Class = Class
--      AC_Type = AC_Get_Type(AC_Class)

      -- We set the visual of the window
      AC_TargetTitle:SetText(name)
     	UIDropDownMenu_SetText(AC_DropDown,AC.ColorClass(Class))
      UIDropDownMenu_SetSelectedValue(AC_DropDown,Class)
      AC_MaxLevel:SetText(Level)
      UIDropDownMenu_SetSelectedValue(AC_CP_DropDown,name)

      local FilterBOP
      if name ~= UnitName("player") then
      	AC_TargetPortrait:SetTexture(Texture)
      	FilterBOP = true
      else
      	SetPortraitTexture(AC_TargetPortrait,"player")
      	FilterBOP = false
      end

--print("CD_DropDown_Onclick: value = %s", value or 'nil')
      if not name then
     		UIDropDownMenu_SetText(AC_CP_DropDown,AC_SELECT)
      end

      -- Proceed to scan
    	AC_ScanTradeSkillWindow(Class,Level,FilterBOP)
    else
    	print(FCr..ARMORCRAFT_UNDEFINED..name)
    end
end

function AC_EnterLevel()
    local level = tonumber(this:GetText())
    if not level or level<1 or level>70 then
      this:HighlightText(0,-1);
      print(FCr..ARMORCRAFT_BADLEVEL)
      return;
    end
    this:ClearFocus()
    AC_Level = level
    --AC_Scan(AC_Level)
    AC_ScanTradeSkillWindow(AC_Class,AC_Level,(ArmorCraft.unit_id~="player"))
end

function AC_Button_OnEnter()
    if this.tsi then
        ArmorCraft_TT1:SetOwner(this, "ANCHOR_LEFT")
        ArmorCraft_TT1:SetTradeSkillItem(this.tsi)
    elseif this.new_item_link then
        ArmorCraft_TT1:SetOwner(this, "ANCHOR_LEFT")
        ArmorCraft_TT1:SetHyperlink(this.new_item_link)
        if this.char_item_link then
			  ArmorCraft_TT2:SetOwner(this, "ANCHOR_RIGHT")
			  ArmorCraft_TT2:SetHyperlink(this.char_item_link)
		  end
    elseif this.slot then
        ArmorCraft_TT1:SetOwner(this, "ANCHOR_RIGHT")
        if type(this.slot)=='number' then
          ArmorCraft_TT1:SetInventoryItem(AC_Unit,this.slot)
        else ArmorCraft_TT1:SetHyperlink(this.slot) end
        local button = getglobal("AC_CraftButton"..this:GetID())
        if button.tsi then
          ArmorCraft_TT2:SetOwner(this, "ANCHOR_LEFT")
          ArmorCraft_TT2:SetTradeSkillItem(button.tsi)
        end
--[[
    elseif this.item then
        ArmorCraft_TT1:SetOwner(this, "ANCHOR_RIGHT")
        ArmorCraft_TT1:SetHyperlink(this.item)
        ArmorCraft_TT2:SetOwner(this, "ANCHOR_LEFT")
        ArmorCraft_TT2:SetHyperlink(AC_Use.item)
]]--
    elseif this.loc then
        ArmorCraft_TT1:SetOwner(this, "ANCHOR_RIGHT")
        ArmorCraft_TT1:SetText(this.loc)
    end
end

function AC_Button_OnClick(button)
    if button=='RightButton' then
      if this.tsi then
        assert(GetTradeSkillItemLink(this.tsi),format("Can't get GetTradeSkillItemLink for %s", this.tsi or 'nil'))
        print(ARMORCRAFT_SKIP..GetTradeSkillItemLink(this.tsi))
        --AC_Skip[this.tsi] = 1
		  ArmorCraft.tradeskill_skip[this.tsi] = true
		  --AC_Scan(AC_Level)
        AC_ScanTradeSkillWindow(AC_Class,AC_Level,(ArmorCraft.unit_id~="player"))
      end
      return
    end
    local av2,dif,link = ''
    if this.tsi then
      link = GetTradeSkillItemLink(this.tsi)
      if ChatFrameEditBox:IsVisible() then
        ChatFrameEditBox:Insert(link)
        return
      end
      TradeSkillFrame_SetSelection(this.tsi)
      local nts = GetNumTradeSkills()
      if nts>TRADE_SKILLS_DISPLAYED then
        local scroll = this.tsi - TRADE_SKILLS_DISPLAYED/2 -1
        if scroll<0 then scroll = 0; end
        if scroll>nts-TRADE_SKILLS_DISPLAYED then
          scroll = nts-TRADE_SKILLS_DISPLAYED
        end
        TradeSkillListScrollFrameScrollBar:SetValue(scroll*16)
      end
      TradeSkillFrame_Update()
      if AC_Target:IsVisible() then
        local name = "AC_TargetButton"..this:GetID()
        local button = getglobal(name)
        if button.av and button.av>0 then
          local label = getglobal(name.."Text"):GetText()
          dif = this.av-button.av
          av2 = format(", %s = %.2f (%+.2f)",label,button.av,dif)
        end
      end
    elseif this.new_item_link then
      if ChatFrameEditBox:IsVisible() then
        ChatFrameEditBox:Insert(ItemLink(this.new_item_link))
        return
      end
      local msg = format("%s = %.2f",ItemLink(this.new_item_link),this.new_item_value)
      if this.char_item_link then
      	msg = msg .. format(", %s = %.2f (%+.2f)",
      							  ItemLink(this.char_item_link),
      							  this.char_item_value,
      							  this.new_item_value-this.char_item_value)
      end
      print(msg)
      return
    elseif this.item then
      if ChatFrameEditBox:IsVisible() then
        ChatFrameEditBox:Insert(ItemLink(this.item))
        return
      end
      link = AC_Link
      dif = this.av-this.aw
      local _, link2 = GetItemInfo(this.item)
      av2 = format(", %s = %.2f (%+.2f)",link2,this.aw,dif)
    else return; end
    print(format("%s = %.2f%s",link,this.av,av2))
end

-- #################################################################################
-- #################################################################################
-- ##
-- ## AC_ScanTradeSkillWindow(class,level,bop)
-- ## ----------------------------------------
-- ##
-- ## Scan the trade skils from the curent trade skill window, find the best
-- ## possible item for each equip slot of the paper dool and display them in
-- ## the AC_FrameTemplate window.
-- ##
-- ## Parameter: class (string)	= Class to use for finding the best items
-- ##            level (number)	= Level of the PC that will use the items
-- ##            bop					= Do not allow Bind on Pickup items
-- ##
-- #################################################################################

function AC_ScanTradeSkillWindow(class,level,bop)
	-- Set up the "best of" table
	local BestFits = {}
	for SlotName,v in pairs(ArmorCraft_Loc) do
		BestFits[v.SlotID] = {["SlotName"]=SlotName,Link=nil,Value=-1,TS_Index=nil,Desc=nil}
	end

	-- First part, scan all the curent trade skills and keep the best items
	for ts_index = 1,GetNumTradeSkills() do
		local ts_name,ts_type = GetTradeSkillInfo(ts_index)
		if ts_type ~= "header" and not ArmorCraft.tradeskill_skip[ts_index] then
			-- Bind the TradeSkill to the hiden ToolTip
			ArmorCraft_TT:SetOwner(AC_Frame)
			ArmorCraft_TT:SetTradeSkillItem(ts_index)

			-- Get the tradeskill item details
			local desc = AC_Parse(bop)
			local link = GetTradeSkillItemLink(ts_index)

			-- Check only admissable items
			if (not desc.bop or not bop) and level >= desc.lvl then
				-- Calculate the item value for each equipable slot
				local _, _, _, _, _, _, _, _, EquipLoc = GetItemInfo(link)
				if EquipLoc and EquipLoc ~= "" and ArmorCraft_EquipWhere[EquipLoc] then
					for _, SlotID in ipairs(ArmorCraft_EquipWhere[EquipLoc]) do
						if AC_CanUseItem(link,class,level) then
							local value = AC_AValue(desc,class,BestFits[SlotID]["SlotName"])
							if value > BestFits[SlotID]["Value"] then
								BestFits[SlotID]["Value"] 		= value
								BestFits[SlotID]["Link"]		= link
								BestFits[SlotID]["TS_Index"]	= ts_index
								BestFits[SlotID]["Desc"]		= desc
							end
						end
					end
				end
			end
		end
	end

	-- Let's display the winners :-)
	for SlotName, ACLoc in pairs (ArmorCraft_Loc) do
		-- The AC_Target window
		local target_value  = -1
		local target_desc

		local button_target = nil
		if ACLoc.ID then button_target = getglobal("AC_TargetButton"..ACLoc.ID) end
		if button_target then
			local label = getglobal("AC_TargetButton"..ACLoc.ID.."Text")

			if ArmorCraft.unit_id == "recorded" then
				-- Get the currently selected name
				local Name = UIDropDownMenu_GetSelectedValue(AC_CP_DropDown)

				-- Get the item in the current slot for this character
				local itemString = AC_GetRecordedCharacterEquip(Name,ACLoc.SlotID)

--print(format("Scan: SlotName = %s, slot = %s, itemString = %s",SlotName or 'nil',ACLoc.slot or 'nil',itemString or 'nil'))

--				local CP_Char_slot_name = strsub(ACLoc.slot,1,-5) -- Ugly

				-- Information from a Character Profiler type addon
				if itemString then

					-- Path to the texture tu use
					local _, _, _, _, _, _, _, _, _, Texture = GetItemInfo(itemString)
					SetItemButtonTexture(button_target,Texture)

					-- Set the hiden tooltip for the parse
					ArmorCraft_TT:SetHyperlink(itemString)

					target_desc = AC_Parse(false) -- bop is not needed here, the target will never have BoP stuff

					target_value = AC_AValue(target_desc,class,SlotName)
					label:SetText(target_desc.name)
					label:SetTextColor(White.r, White.g, White.b)

					-- This will be used by OnEnter to display the tooltip
					button_target.slot = itemString
					button_target.av   = target_value

				else
					local _, texture = GetInventorySlotInfo(ACLoc.slot)
					SetItemButtonTexture(button_target,texture)
					label:SetText('')
					button_target.slot = nil
					button_target.av   = nil
				end
			else
--print(format("Scan: SlotName = %s, slot = %s, unit_id = %s, SlotID = %s",SlotName or 'nil',ACLoc.slot or 'nil',ArmorCraft.unit_id or 'nil',ACLoc.SlotID or 'nil'))
				-- In game information
				local texture = GetInventoryItemTexture(ArmorCraft.unit_id,ACLoc.SlotID)
				if not texture then _, texture = GetInventorySlotInfo(ACLoc.slot) end
				SetItemButtonTexture(button_target,texture)

				-- Bind the TradeSkill to the hiden ToolTip
				if ArmorCraft_TT:SetInventoryItem(ArmorCraft.unit_id,ACLoc.SlotID) then
					target_desc = AC_Parse(false) -- bop is not needed here, the target will never have BoP stuff

					target_value = AC_AValue(target_desc,class,SlotName)
					label:SetText(target_desc.name)
					label:SetTextColor(White.r, White.g, White.b)

					-- This will be used by OnEnter to display the tooltip
					button_target.slot = ACLoc.SlotID
					button_target.av   = target_value

				else
					label:SetText('')
					button_target.slot = nil
					button_target.av   = nil
				end
			end
		end

		-- The AC_Craft window
		local button_craft = nil
		if ACLoc.ID then button_craft = getglobal("AC_CraftButton"..ACLoc.ID) end
		if button_craft ~= nil then
			local label = getglobal("AC_CraftButton"..ACLoc.ID.."Text")

			-- Use the good values if there otherwise but bad non usable value
			button_craft.tsi = BestFits[ACLoc.SlotID]['TS_Index']
			button_craft.av  = BestFits[ACLoc.SlotID]['Value']

			if ACLoc.ID and ACLoc.SlotID and BestFits[ACLoc.SlotID]['Link'] then
				-- We have a best item to show
				SetItemButtonTexture(button_craft,GetTradeSkillIcon(button_craft.tsi))
				label:SetText(BestFits[ACLoc.SlotID]['Desc']['name'])

				-- Set the text colour
				local color = White
				if     BestFits[ACLoc.SlotID]['Value'] > target_value+2  then color = Green
				elseif BestFits[ACLoc.SlotID]['Value'] < target_value-10 then color = Gray
				end
				label:SetTextColor(color.r, color.g, color.b)
			else
				-- The button is empty
				local _, texture = GetInventorySlotInfo(ACLoc.slot)
				SetItemButtonTexture(button_craft,texture)
				label:SetText('')
			end
		end

	end
end


-- #################################################################################
-- #################################################################################
-- ##
-- ## AC_Parse(bop)
-- ## -------------
-- ##
-- ## Scan the tooltip and return information about the item
-- ##
-- ## Parameter: bop (boolean)  = True if Binds when Pickup should be ignored
-- ##
-- ## desc.name  			= Name of the item
-- ## desc.link  			= Hyperlink for the item
-- ## desc.boe   			= True is the item is bind on equip
-- ## desc.bop   			= True if the tiem is bind on pickup
-- ## desc.lvl   			= Level requirement for the item
-- ## desc.loc   			= Location that the item can be equiped (plain english)
-- ## desc.itemEquipLoc	= Location that the item can be equiped (from GetItemInfo)
-- ## desc.type  			= Type of item
-- ## desc.ac    			= Armor Class
-- ## desc.dps   			= DPS if it is a weapon
-- ## desc.av    			= table with the values for STR, STAM, DEX, etc.
-- ##
-- #################################################################################


function AC_Parse(bop)
    local n = ArmorCraft_TT:NumLines()
    local i,line = AC_NextLine(1)
    local desc = {name=line,lvl=0,ac=0,av={}}
    i,line = AC_NextLine(i)
    if line==ARMORCRAFT_SOULBOUND then
      i,line = AC_NextLine(i)
    elseif line==ARMORCRAFT_BOE or line==ARMORCRAFT_BOU then
      desc.boe = true
      i,line = AC_NextLine(i)
    elseif line==ARMORCRAFT_BOP then
      desc.bop = true
      if bop then return desc end
      i,line = AC_NextLine(i)
    end
    if line==ARMORCRAFT_UNIQUE_EQUIPPED then
      i,line = AC_NextLine(i)
    end
    if line==ARMORCRAFT_UNIQUE then
      i,line = AC_NextLine(i)
    end
    desc.type = getglobal("ArmorCraft_TTTextRight"..(i-1)):GetText()
    if line==AC_GUN then
      desc.loc = AC_RANGED
      desc.type = AC_GUN
    else desc.loc = line end
    if i>n then return desc end
    i,line = AC_NextLine(i)
    local s,e,nr = string.find(line,ARMORCRAFT_ARMOR)
    if s then desc.ac = tonumber(nr) end
    local str
    while i<=n do
      i,line = AC_NextLine(i)
      s,e,nr,str = string.find(line,"^%+(%d+) (%a+)")
      if s then desc.av[str] = tonumber(nr)
      else
        s,e,nr = string.find(line,ARMORCRAFT_REQUIRES)
        if s then desc.lvl = tonumber(nr)
        else
          s,e,nr = string.find(line,ARMORCRAFT_DPS)
          if s then desc.dps = tonumber(nr) end
        end
      end
    end
    desc.name, desc.link = ArmorCraft_TT:GetItem()
    if desc.link then
    	local GI_type, GI_subtype, GI_loc
    	_, _, _, _, desc.lvl, GI_type, GI_subtype, _, GI_loc = GetItemInfo(desc.link)
    	if GI_loc then
    		desc.itemEquipLoc	= GI_loc
    		desc.loc 			= _G[GI_loc]
    	end
    	if not desc.type and GI_subtype then
    		desc.type = GI_subtype
    	end
--print(FCr.."AC_Use: link = "..(desc.link)..", type = "..(GI_type or "nil")
--      ..", subtype = "..(GI_subtype or "nil")..", loc = "..(_G[GI_loc] or "nil"))
	 end
    return desc
end



function AC_NextLine(ix)
    local ttf = getglobal("ArmorCraft_TTTextLeft"..ix)
    return ix+1, ttf:GetText()
end

-- I have to make sure that the Variable are loaded and that the player is loged in.
-- I'm not sure if the order of those two event are already the same
local are_variables_loaded, is_player_logedin = false, false

function AC_OnEvent(frame,event,...)

	if(event=="VARIABLES_LOADED" or event=="PLAYER_LOGIN") then
		if     event=="VARIABLES_LOADED" then are_variables_loaded = true
		elseif event=="PLAYER_LOGIN" 		then is_player_logedin = true end
		if are_variables_loaded and is_player_logedin then ArmorCraft_Init() end

	elseif(event=="TRADE_SKILL_SHOW") then

	elseif(event=="TRADE_SKILL_CLOSE") then HideUIPanel(AC_Craft); HideUIPanel(AC_Use);

	elseif(event=="SKILL_LINES_CHANGED") then
	  local tsname = GetTradeSkillLine();
	  if(AC_tsname~=tsname) then
		HideUIPanel(AC_Craft);
		if(ArmorCraft_TS[tsname]) then
		  AC_ToggleButton:Enable();
		  AC_UseButton:Enable();
		else
		  AC_ToggleButton:Disable();
		  AC_UseButton:Disable();
		end
	  end
	end

end

-- Patching frames to handle dynamic loading
function AC_SetFrames()
    AC_Craft:SetParent(TradeSkillFrame);
    AC_Craft:SetPoint("TOPLEFT","TradeSkillFrame","TOPRIGHT",-40,100)
    AC_ToggleButton:SetParent(TradeSkillFrame)
    AC_ToggleButton:SetFrameLevel(TradeSkillFrame:GetFrameLevel()+3)
    AC_UseButton:SetPoint("RIGHT","AC_ToggleButton","LEFT")
    AC_SetFrames = function() end
end

if not TradeSkillFrame then
  local AC_TS_Load = TradeSkillFrame_LoadUI
  TradeSkillFrame_LoadUI = function() AC_TS_Load(); AC_SetFrames() end
end

-- #################################################################################
-- #################################################################################
-- ##
-- ## AC_CanUseItem(link,class,level)
-- ## -------------------------------
-- ##
-- ## Return true if the item can be use for this class at that level
-- ##
-- ## Parameters: link				= link to the item to check
-- ##				   class (string)	= class that would use the item
-- ##             level (number)	= level of the PC that would use the item
-- ##             					  (optional, default value 70)
-- ##
-- #################################################################################

function AC_CanUseItem(link,class,level)
--print(format("CanUseItem: link = %s, class = %s, level = %s",link or 'nil',class or 'nil',level or 'nil'))
	--  A bit of protection here
--	link = ItemLink(link)

	-- Find some information about the item
	local _, _, _, _, MinLevel, Type, SubType, _, EquipLoc = GetItemInfo(link)
	if not Type then return false end
--print(format("CanUseItem: MinLevel = %s, Type = %s, SubType = %s",MinLevel,Type,SubType))

	-- Level requirement
	if not level then level = 80 end
	if level < MinLevel then return false end

	-- Location requirement


	if Type == AC_ARMOR then
		-- Armor
		if ArmorCraft_CanUse[class][AC_ARMOR][SubType] <= level then
			return true
		else
			return false
		end
	elseif Type == AC_WEAPON then
		if ArmorCraft_CanUse[class][AC_WEAPON][SubType] <= level then
			return true
		else
			return false
		end
	else
		-- ArmorCraft is only for armor or weapon i.e. stuff that is wearable
		return false
	end

	return false
end

-- #################################################################################
-- #################################################################################
-- ##
-- ## AC_InitRecordedCharacter()
-- ## --------------------------
-- ##
-- ## Do the initial setup of the AC_CP_DropDown that contains all the recorded
-- ## characters and store informations about them that will be used later
-- ##
-- #################################################################################

function AC_InitRecordedCharacter()
	if ArmorCraftCacheDB then
		-- Support for ArmorCraftCache
		ArmorCraft.recorder = 'ArmorCraftCache'

		local faction   = UnitFactionGroup("player")
		local realm     = GetRealmName()

		if ArmorCraftCacheDB[faction][realm] then
			ArmorCraft.recorded_name_list = {}

			for name,data in pairs(ArmorCraftCacheDB[faction][realm]) do
				if not AC_Ignore[realm..':'..name] then
					tinsert(ArmorCraft.recorded_name_list,name)
				end
			end

			ArmorCraft.recorded_number = getn(ArmorCraft.recorded_name_list)
			table.sort(ArmorCraft.recorded_name_list)

			if ArmorCraft.recorded_number>1 then
				AC_CP_DropDown:Show()
			end
		end

	elseif myProfile then
		-- Support for RPGO CharacterProfiler
		ArmorCraft.recorder = 'RPGO CharacterProfiler'

		local Server = GetCVar("realmName")

--		AC_CP_Chars = myProfile[Server]["Character"]
		if myProfile[Server]["Character"] then
			ArmorCraft.recorded_name_list = {}

			for name,data in pairs(myProfile[Server]["Character"]) do
				tinsert(ArmorCraft.recorded_name_list,name)
			end

			ArmorCraft.recorded_number = getn(ArmorCraft.recorded_name_list)
			table.sort(ArmorCraft.recorded_name_list)

			if ArmorCraft.recorded_number>1 then
				AC_CP_DropDown:Show()
			end

			-- Legacy code
			AC_CP_Chars = myProfile[Server]["Character"]
		end
	end

end

-- #################################################################################
-- #################################################################################
-- ##
-- ## AC_GetRecordedCharacterInfo(name)
-- ## ---------------------------------
-- ##
-- ## Return the information for a recorded charracter
-- ##
-- ## Parameter:	name			= Name of the character
-- ##
-- ## Return:		charClass	= Character class
-- ## 				charLevel	= Character level
-- ## 				charPicTex	= Path to the texture to use for the character
-- ##
-- #################################################################################

local RPGOSexDesc = {
	[0]	= "Male",
	[1]	= "Female",
}
local RPGORaceDesc = {
	[1]	= 'Human',
	[2] 	= 'Orc',
	[3]	= 'Dwarf',
	[4]	= 'NightElf',
	[5]	= 'Scourge',
	[6]	= 'Tauren',
	[7]	= 'Gnome',
	[8]	= 'Troll',
	[10]	= 'BloodElf',
	[11]	= 'Draenei',
}
local ACCacheSexDesc = {
	[2]	= 'Male',
	[3]	= 'Female',
}
function AC_GetRecordedCharacterInfo(name)

	if ArmorCraft.recorder == 'ArmorCraftCache' then

		local faction   = UnitFactionGroup("player")
		local realm     = GetRealmName()

		if ArmorCraftCacheDB[faction][realm][name] then
			local texture
			local sex 		= ACCacheSexDesc[ArmorCraftCacheDB[faction][realm][name].sex]
			local race		= ArmorCraftCacheDB[faction][realm][name].race
			if sex and race then
				texture = "Interface\\CharacterFrame\\TemporaryPortrait-" .. sex .. "-" .. race
			else
				texture = "Interface\\CharacterFrame\\TemporaryPortrait"
			end

			return ArmorCraftCacheDB[faction][realm][name].class,
			       ArmorCraftCacheDB[faction][realm][name].level,
			       texture
		else
			print(FCr.."Error: ArmorCraftCache doesn't know "..name or 'nil')
			return nil
		end

	elseif ArmorCraft.recorder == 'RPGO CharacterProfiler' then

		-- Specific support for RPGO CharacterProfiler
		local Server = GetCVar("realmName")
--print(format("GetCharInfo: Server = %s, name = %s",Server or 'nil',name or 'nil'))
		if myProfile[Server]["Character"][name] then
			local texture
			local sex  = RPGOSexDesc[myProfile[Server]["Character"][name]["SexId"]]
			local race = RPGORaceDesc[myProfile[Server]["Character"][name]["RaceId"]]
			if sex and race then
				texture = "Interface\\CharacterFrame\\TemporaryPortrait-" .. sex .. "-" .. race
			else
				texture = "Interface\\CharacterFrame\\TemporaryPortrait"
			end

			return myProfile[Server]["Character"][name]["Class"],
				    myProfile[Server]["Character"][name]["Level"],
				    texture
		else
			print(FCr.."Error: RPGO doesn't know "..name)
			return nil
		end

	else
		return nil
	end
end

-- #################################################################################
-- #################################################################################
-- ##
-- ## AC_GetRecordedCharacterEquip(name,slotName)
-- ## -------------------------------------------
-- ##
-- ## Return the information for a recorded charracter
-- ##
-- ## Parameter:	name			= Name of the character
-- ## 				slotID		= ID of the slot as returned by GetInventorySlotInfo
-- ##
-- ## Return:		itemString	= Description of the item in the itemString format
-- ##
-- #################################################################################

function AC_GetRecordedCharacterEquip(name,slotID)
	local faction   = UnitFactionGroup("player")
	local realm     = GetRealmName()

	if ArmorCraft.recorder == 'ArmorCraftCache' then
		return ArmorCraftCacheDB[faction][realm][name].items[slotID]
	elseif ArmorCraft.recorder == 'RPGO CharacterProfiler' then
		local slotName = slotID
		if type(slotID) == 'number' then slotName = ArmorCraft.ID_to_slotname[slotID] or "" end
		local RPGOSlotName = strsub(slotName,1,-5)
--print(format("GetCharInfo: realm = %s, name = %s, RPGOSlotName = %s, slotName = %s",realm or 'nil',name or 'nil',RPGOSlotName or 'nil',slotName or 'nil'))
		if myProfile[realm]["Character"][name]["Equipment"][RPGOSlotName] then
			return "item:"..myProfile[realm]["Character"][name]["Equipment"][RPGOSlotName]["Item"]
		else
			return nil
		end
	else
		return nil
	end
end

-- #################################################################################
-- #################################################################################
-- ##
-- ## AC.GetClassColor(class)
-- ## -----------------------
-- ##
-- ## Return the RGB numbers for a specific character class
-- ##
-- ## Note: this function was taken nearly verbatim from the Bable-Class library
-- ##
-- ## Parameter: 	class		= Class name not localised
-- ##
-- ## Return:		rClass	= red value for the class color
-- ##  				gClass	= green value for the class color
-- ##					bClass	= blue value for the class color
-- ##
-- #################################################################################

function AC.GetClassColor(class)
	-- Ugly hack, I know
	if class == AC_DEATHKNIGHT then
		class = 'DEATHKNIGHT'
	else
		class = string.upper(class)
	end

	if RAID_CLASS_COLORS and RAID_CLASS_COLORS[class] then
		return RAID_CLASS_COLORS[class].r, RAID_CLASS_COLORS[class].g, RAID_CLASS_COLORS[class].b
	end
	return 0.63, 0.63, 0.63
end

-- #################################################################################
-- #################################################################################
-- ##
-- ## AC.ColorClass(class)
-- ## --------------------
-- ##
-- ## Return the HEX color string for a specific character class
-- ##
-- ## Note: this function was taken nearly verbatim from the Bable-Class library
-- ##
-- ## Parameter: 	class				= Class name not localised
-- ##
-- ## Return:		coloredClass	= Class name with the proper color hex codes
-- ##
-- #################################################################################

function AC.ColorClass(class)
	local r, g, b = AC.GetClassColor(class)
	return string.format("|cff%02x%02x%02x%s|r", r * 255, g * 255, b * 255,class)
end


